home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / dist-packages / apport / packaging_impl.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-10-12  |  31.5 KB  |  928 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''An apport.PackageInfo class implementation for python-apt and dpkg, as found
  5. on Debian and derivatives such as Ubuntu.
  6.  
  7. Copyright (C) 2007, 2009 Canonical Ltd.
  8. Author: Martin Pitt <martin.pitt@ubuntu.com>
  9.  
  10. This program is free software; you can redistribute it and/or modify it
  11. under the terms of the GNU General Public License as published by the
  12. Free Software Foundation; either version 2 of the License, or (at your
  13. option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
  14. the full text of the license.
  15. '''
  16. import subprocess
  17. import os
  18. import glob
  19. import stat
  20. import sys
  21. import tempfile
  22. import glob
  23. import re
  24. import shutil
  25. import warnings
  26. warnings.filterwarnings('ignore', 'apt API not stable yet', FutureWarning)
  27. import apt
  28. from apport.packaging import PackageInfo
  29.  
  30. class __AptDpkgPackageInfo(PackageInfo):
  31.     '''Concrete apport.PackageInfo class implementation for python-apt and
  32.     dpkg, as found on Debian and derivatives such as Ubuntu.'''
  33.     
  34.     def __init__(self):
  35.         self._apt_cache = None
  36.         self._contents_dir = None
  37.         self._mirror = None
  38.         self.configuration = '/etc/default/apport'
  39.  
  40.     
  41.     def __del__(self):
  42.         
  43.         try:
  44.             if self._contents_dir:
  45.                 import shutil
  46.                 shutil.rmtree(self._contents_dir)
  47.         except AttributeError:
  48.             pass
  49.  
  50.  
  51.     
  52.     def _cache(self, package):
  53.         '''Return apt.Cache()[package] (initialized lazily).
  54.         
  55.         Throw a ValueError if the package does not exist.'''
  56.         if not self._apt_cache:
  57.             self._apt_cache = apt.Cache()
  58.         
  59.         
  60.         try:
  61.             return self._apt_cache[package]
  62.         except KeyError:
  63.             raise ValueError, 'package does not exist'
  64.  
  65.  
  66.     
  67.     def get_version(self, package):
  68.         '''Return the installed version of a package.'''
  69.         return self._cache(package).installedVersion
  70.  
  71.     
  72.     def get_available_version(self, package):
  73.         '''Return the latest available version of a package.'''
  74.         return self._cache(package).candidateVersion
  75.  
  76.     
  77.     def get_dependencies(self, package):
  78.         '''Return a list of packages a package depends on.'''
  79.         cur_ver = self._cache(package)._pkg.CurrentVer
  80.         if not cur_ver:
  81.             return []
  82.         return [ d[0].TargetPkg.Name for d in cur_ver.DependsList.get('Depends', []) + cur_ver.DependsList.get('PreDepends', []) ]
  83.  
  84.     
  85.     def get_source(self, package):
  86.         '''Return the source package name for a package.'''
  87.         return self._cache(package).sourcePackageName
  88.  
  89.     
  90.     def is_distro_package(self, package):
  91.         '''Check if a package is a genuine distro package (True) or comes from
  92.         a third-party source.'''
  93.         lsb_release = subprocess.Popen([
  94.             'lsb_release',
  95.             '-i',
  96.             '-s'], stdout = subprocess.PIPE)
  97.         this_os = lsb_release.communicate()[0].strip()
  98.         if not lsb_release.returncode == 0:
  99.             raise AssertionError
  100.         if self._cache(package).installedVersion is None:
  101.             return False
  102.         origins = self._cache(package).candidateOrigin
  103.         return False
  104.  
  105.     
  106.     def get_architecture(self, package):
  107.         '''Return the architecture of a package.
  108.  
  109.         This might differ on multiarch architectures (e. g.  an i386 Firefox
  110.         package on a x86_64 system)'''
  111.         if not self._cache(package).architecture:
  112.             pass
  113.         return 'unknown'
  114.  
  115.     
  116.     def get_files(self, package):
  117.         '''Return list of files shipped by a package.'''
  118.         list = self._call_dpkg([
  119.             '-L',
  120.             package])
  121.         if list is None:
  122.             return None
  123.         return _[1]
  124.  
  125.     
  126.     def get_modified_files(self, package):
  127.         '''Return list of all modified files of a package.'''
  128.         listfile = '/var/lib/dpkg/info/%s.list' % package
  129.         
  130.         try:
  131.             s = os.stat(listfile)
  132.             if not stat.S_ISREG(s.st_mode):
  133.                 raise OSError
  134.             stat.S_ISREG(s.st_mode)
  135.             max_time = max(s.st_mtime, s.st_ctime)
  136.         except OSError:
  137.             return [
  138.                 listfile]
  139.  
  140.         sums = ''
  141.         sumfile = '/var/lib/dpkg/info/%s.md5sums' % package
  142.         if not os.path.exists(sumfile):
  143.             return []
  144.         for line in open(sumfile):
  145.             
  146.             try:
  147.                 words = line.split()
  148.                 s = os.stat('/' + words[-1])
  149.                 if max(s.st_mtime, s.st_ctime) <= max_time:
  150.                     continue
  151.             except OSError:
  152.                 os.path.exists(sumfile)
  153.                 os.path.exists(sumfile)
  154.             except:
  155.                 os.path.exists(sumfile)
  156.  
  157.             sums += line
  158.         
  159.         if sums:
  160.             return self._check_files_md5(sums)
  161.         return []
  162.  
  163.     
  164.     def _AptDpkgPackageInfo__fgrep_files(self, pattern, file_list):
  165.         '''Call fgrep for a pattern on given file list and return the first
  166.         matching file, or None if no file matches.'''
  167.         match = None
  168.         slice_size = 100
  169.         i = 0
  170.         while not match and i < len(file_list):
  171.             p = subprocess.Popen([
  172.                 'fgrep',
  173.                 '-lxm',
  174.                 '1',
  175.                 '--',
  176.                 pattern] + file_list[i:i + slice_size], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True)
  177.             out = p.communicate()[0]
  178.             if p.returncode == 0:
  179.                 match = out
  180.             
  181.             i += slice_size
  182.         return match
  183.  
  184.     
  185.     def get_file_package(self, file, uninstalled = False, map_cachedir = None):
  186.         '''Return the package a file belongs to, or None if the file is not
  187.         shipped by any package.
  188.         
  189.         If uninstalled is True, this will also find files of uninstalled
  190.         packages; this is very expensive, though, and needs network access and
  191.         lots of CPU and I/O resources. In this case, map_cachedir can be set to
  192.         an existing directory which will be used to permanently store the
  193.         downloaded maps. If it is not set, a temporary directory will be used.'''
  194.         dpkg = subprocess.Popen([
  195.             '/usr/sbin/dpkg-divert',
  196.             '--list',
  197.             file], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  198.         out = dpkg.communicate()[0]
  199.         if dpkg.returncode == 0 and out:
  200.             return out.split()[-1]
  201.         fname = os.path.splitext(os.path.basename(file))[0].lower()
  202.         all_lists = []
  203.         likely_lists = []
  204.         for f in glob.glob('/var/lib/dpkg/info/*.list'):
  205.             p = os.path.splitext(os.path.basename(f))[0].lower()
  206.             if p in fname or fname in p:
  207.                 likely_lists.append(f)
  208.                 continue
  209.             out
  210.             all_lists.append(f)
  211.         
  212.         match = self._AptDpkgPackageInfo__fgrep_files(file, likely_lists)
  213.         if not match:
  214.             match = self._AptDpkgPackageInfo__fgrep_files(file, all_lists)
  215.         
  216.         if match:
  217.             return os.path.splitext(os.path.basename(match))[0]
  218.         if uninstalled:
  219.             return self._search_contents(file, map_cachedir)
  220.         return None
  221.  
  222.     
  223.     def get_system_architecture(self):
  224.         '''Return the architecture of the system, in the notation used by the
  225.         particular distribution.'''
  226.         dpkg = subprocess.Popen([
  227.             'dpkg',
  228.             '--print-architecture'], stdout = subprocess.PIPE)
  229.         arch = dpkg.communicate()[0].strip()
  230.         if not dpkg.returncode == 0:
  231.             raise AssertionError
  232.         if not arch:
  233.             raise AssertionError
  234.         return arch
  235.  
  236.     
  237.     def set_mirror(self, url):
  238.         '''Explicitly set a distribution mirror URL for operations that need to
  239.         fetch distribution files/packages from the network.
  240.  
  241.         By default, the mirror will be read from the system configuration
  242.         files.'''
  243.         self._mirror = url
  244.  
  245.     
  246.     def get_source_tree(self, srcpackage, dir, version = None):
  247.         '''Download given source package and unpack it into dir (which should
  248.         be empty).
  249.  
  250.         This also has to care about applying patches etc., so that dir will
  251.         eventually contain the actually compiled source.
  252.  
  253.         If version is given, this particular version will be retrieved.
  254.         Otherwise this will fetch the latest available version.
  255.  
  256.         Return the directory that contains the actual source root directory
  257.         (which might be a subdirectory of dir). Return None if the source is
  258.         not available.'''
  259.         argv = [
  260.             'apt-get',
  261.             '--assume-yes',
  262.             'source',
  263.             srcpackage]
  264.         if version:
  265.             argv[-1] += '=' + version
  266.         
  267.         
  268.         try:
  269.             if subprocess.call(argv, stdout = subprocess.PIPE, cwd = dir) != 0:
  270.                 return None
  271.         except OSError:
  272.             return None
  273.  
  274.         root = None
  275.         for d in glob.glob(os.path.join(dir, srcpackage + '-*')):
  276.             if os.path.isdir(d):
  277.                 root = d
  278.                 continue
  279.         
  280.         if not root:
  281.             raise AssertionError, 'could not determine source tree root directory'
  282.         
  283.         try:
  284.             subprocess.call('debian/rules patch || debian/rules apply-patches || debian/rules apply-dpatches || debian/rules unpack || debian/rules patch-stamp || debian/rules setup', shell = True, cwd = root, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  285.         except OSError:
  286.             root
  287.             root
  288.         except:
  289.             root
  290.  
  291.         return root
  292.  
  293.     
  294.     def get_kernel_package(self):
  295.         '''Return the actual Linux kernel package name.
  296.  
  297.         This is used when the user reports a bug against the "linux" package.
  298.         '''
  299.         return 'linux-image-' + os.uname()[2]
  300.  
  301.     
  302.     def install_retracing_packages(self, report, verbosity = 0, unpack_only = False, no_pkg = False, extra_packages = []):
  303.         '''Install packages which are required to retrace a report.
  304.         
  305.         If package installation fails (e. g. because the user does not have root
  306.         privileges), the list of required packages is printed out instead.
  307.  
  308.         If unpack_only is True, packages are only temporarily unpacked and
  309.         purged again after retrace, instead of permanently and fully installed.
  310.         If no_pkg is True, the package manager is not used at all, but the
  311.         binary packages are just unpacked with low-level tools; this speeds up
  312.         operations in fakechroots, but makes it impossible to cleanly remove
  313.         the package, so only use that in apport-chroot.
  314.         
  315.         Return a tuple (list of installed packages, string with outdated packages).
  316.         '''
  317.         self._cache('bash')
  318.         c = self._apt_cache
  319.         
  320.         try:
  321.             if verbosity:
  322.                 c.update(apt.progress.TextFetchProgress())
  323.             else:
  324.                 c.update()
  325.             c.open(apt.progress.OpProgress())
  326.         except SystemError:
  327.             e = None
  328.             if 'Hash Sum mismatch' in str(e):
  329.                 print >>sys.stderr, str(e), 'aborting'
  330.                 sys.exit(99)
  331.             else:
  332.                 raise 
  333.             'Hash Sum mismatch' in str(e)
  334.             except apt.cache.LockFailedException:
  335.                 if os.geteuid() != 0:
  336.                     print >>sys.stderr, 'WARNING: Could not update apt, you need to be root'
  337.                 else:
  338.                     raise 
  339.                 os.geteuid() != 0
  340.             else:
  341.                 installed = []
  342.                 uninstallable = []
  343.                 outdated = ''
  344.                 dependency_versions = { }
  345.                 for l in (report['Package'] + '\n' + report.get('Dependencies', '')).splitlines():
  346.                     if not l.strip():
  347.                         continue
  348.                     
  349.                     (pkg, version) = l.split()[:2]
  350.                     dependency_versions[pkg] = version
  351.                     
  352.                     try:
  353.                         if not c[pkg]._lookupRecord():
  354.                             raise KeyError
  355.                         c[pkg]._lookupRecord()
  356.                         if 'Architecture: all' not in c[pkg]._records.Record:
  357.                             dependency_versions[pkg + '-dbgsym'] = dependency_versions[pkg]
  358.                     continue
  359.                     except KeyError:
  360.                         print >>sys.stderr, 'WARNING: package %s not known to package cache' % pkg
  361.                         continue
  362.                     
  363.  
  364.                 
  365.  
  366.         for pkg, ver in dependency_versions.iteritems():
  367.             if (ver or c[pkg].installedVersion == ver or not ver) and c[pkg].installedVersion:
  368.                 continue
  369.             
  370.             if ver and c[pkg].candidateVersion != ver:
  371.                 if not pkg.endswith('-dbgsym'):
  372.                     outdated += '%s: installed version %s, latest version: %s\n' % (pkg, ver, c[pkg].candidateVersion)
  373.                 
  374.                 print >>sys.stderr, 'WARNING: %s version %s required, but %s is available' % (pkg, ver, c[pkg].candidateVersion)
  375.                 if not unpack_only:
  376.                     uninstallable.append(c[pkg].name)
  377.                     continue
  378.                 
  379.             
  380.             c[pkg].markInstall(False)
  381.         
  382.         for p in extra_packages:
  383.             c[p].markInstall(False)
  384.         
  385.         if verbosity:
  386.             fetchProgress = apt.progress.TextFetchProgress()
  387.             installProgress = apt.progress.InstallProgress()
  388.         else:
  389.             fetchProgress = apt.progress.FetchProgress()
  390.             installProgress = apt.progress.DumbInstallProgress()
  391.         
  392.         try:
  393.             if c.getChanges():
  394.                 os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
  395.                 if unpack_only:
  396.                     self.fetch_unpack(c, fetchProgress, no_pkg, verbosity)
  397.                 else:
  398.                     
  399.                     try:
  400.                         c.commit(fetchProgress, installProgress)
  401.                     except SystemError:
  402.                         print >>sys.stderr, 'Error: Could not install all archives. If you use this tool on a production system, it is recommended to use the -u option. See --help for details.'
  403.                         sys.exit(1)
  404.  
  405.                 installed = [ p.name for p in c.getChanges() ]
  406.                 c = apt.Cache()
  407.         except IOError:
  408.             e = None
  409.  
  410.         libs = set()
  411.         if report.has_key('ProcMaps'):
  412.             for l in report['ProcMaps'].splitlines():
  413.                 if not l.strip():
  414.                     continue
  415.                 
  416.                 cols = l.split()
  417.                 if 'x' in cols[1] and len(cols) == 6 and '.so' in cols[5]:
  418.                     lib = os.path.realpath(cols[5])
  419.                     libs.add(lib)
  420.                     continue
  421.             
  422.         
  423.         for l in libs:
  424.             if os.path.exists('/usr/lib/debug' + l):
  425.                 continue
  426.             
  427.             pkg = self.get_file_package(l, True)
  428.             if pkg:
  429.                 if not os.path.exists(l):
  430.                     if pkg in uninstallable:
  431.                         print >>sys.stderr, 'WARNING: %s cannot be installed (incompatible version)' % pkg
  432.                         continue
  433.                     
  434.                     if c.has_key(pkg):
  435.                         c[pkg].markInstall(False)
  436.                     else:
  437.                         print >>sys.stderr, 'WARNING: %s was loaded at runtime, but its package %s is not available' % (l, pkg)
  438.                 
  439.                 if c.has_key(pkg + '-dbgsym') and pkg + '-dbgsym' not in uninstallable:
  440.                     c[pkg + '-dbgsym'].markInstall(False)
  441.                 else:
  442.                     print >>sys.stderr, 'WARNING: %s-dbgsym is not available or is incompatible' % pkg
  443.             pkg + '-dbgsym' not in uninstallable
  444.             print >>sys.stderr, 'WARNING: %s is needed, but cannot be mapped to a package' % l
  445.         
  446.         
  447.         try:
  448.             if c.getChanges():
  449.                 os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
  450.                 if unpack_only:
  451.                     self.fetch_unpack(c, fetchProgress, no_pkg, verbosity)
  452.                 else:
  453.                     c.commit(fetchProgress, installProgress)
  454.             
  455.             [] += [ p.name for p in c.getChanges() ]
  456.         except (SystemError, IOError):
  457.             e = None
  458.             print >>sys.stderr, 'WARNING: could not install missing packages:', e
  459.             if os.geteuid() != 0:
  460.                 print >>sys.stderr, 'You either need to call this program as root or install these packages manually:'
  461.             
  462.             for p in c.getChanges():
  463.                 print >>sys.stderr, '  %s %s' % (p.name, p.candidateVersion)
  464.             
  465.  
  466.         return (installed, outdated)
  467.  
  468.     
  469.     def remove_packages(self, packages, verbosity = 0):
  470.         '''Remove packages.
  471.  
  472.         This is called after install_retracing_packages() to clean up again
  473.         afterwards. packages is a list of package names.
  474.         '''
  475.         if verbosity > 0:
  476.             so = sys.stderr
  477.         else:
  478.             so = subprocess.PIPE
  479.         subprocess.call([
  480.             'dpkg',
  481.             '-P'] + packages, stdout = so)
  482.  
  483.     
  484.     def _call_dpkg(self, args):
  485.         '''Call dpkg with given arguments and return output, or return None on
  486.         error.'''
  487.         dpkg = subprocess.Popen([
  488.             'dpkg'] + args, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  489.         out = dpkg.communicate(input)[0]
  490.         if dpkg.returncode == 0:
  491.             return out
  492.         raise ValueError, 'package does not exist'
  493.  
  494.     
  495.     def _check_files_md5(self, sumfile):
  496.         '''Internal function for calling md5sum.
  497.  
  498.         This is separate from get_modified_files so that it is automatically
  499.         testable.'''
  500.         if os.path.exists(sumfile):
  501.             m = subprocess.Popen([
  502.                 '/usr/bin/md5sum',
  503.                 '-c',
  504.                 sumfile], stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True, cwd = '/', env = { })
  505.             out = m.communicate()[0]
  506.         else:
  507.             m = subprocess.Popen([
  508.                 '/usr/bin/md5sum',
  509.                 '-c'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True, cwd = '/', env = { })
  510.             out = m.communicate(sumfile)[0]
  511.         if m.returncode == 0:
  512.             return []
  513.         mismatches = []
  514.         for l in out.splitlines():
  515.             if l.endswith('FAILED'):
  516.                 mismatches.append(l.rsplit(':', 1)[0])
  517.                 continue
  518.             m.returncode == 0
  519.         
  520.         return mismatches
  521.  
  522.     
  523.     def _get_mirror(self):
  524.         '''Return the distribution mirror URL.
  525.  
  526.         If it has not been set yet, it will be read from the system
  527.         configuration.'''
  528.         if not self._mirror:
  529.             for l in open('/etc/apt/sources.list'):
  530.                 fields = l.split()
  531.                 if len(fields) >= 3 and fields[0] == 'deb' and fields[1].startswith('http://'):
  532.                     self._mirror = fields[1]
  533.                     break
  534.                     continue
  535.             else:
  536.                 raise SystemError, 'cannot determine default mirror: /etc/apt/sources.list does not contain a valid deb line'
  537.         return self._mirror
  538.  
  539.     
  540.     def _search_contents(self, file, map_cachedir):
  541.         '''Internal function for searching file in Contents.gz.'''
  542.         if map_cachedir:
  543.             dir = map_cachedir
  544.         elif not self._contents_dir:
  545.             self._contents_dir = tempfile.mkdtemp()
  546.         
  547.         dir = self._contents_dir
  548.         arch = self.get_system_architecture()
  549.         map = os.path.join(dir, 'Contents-%s.gz' % arch)
  550.         if file.startswith('/'):
  551.             file = file[1:]
  552.         
  553.         package = None
  554.         zgrep = subprocess.Popen([
  555.             'zgrep',
  556.             '-m1',
  557.             '^%s[[:space:]]' % file,
  558.             map], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  559.         out = zgrep.communicate()[0]
  560.         if out:
  561.             package = out.split()[1].split(',')[0].split('/')[-1]
  562.         
  563.         return package
  564.  
  565.     
  566.     def compare_versions(self, ver1, ver2):
  567.         '''Compare two package versions.
  568.  
  569.         Return -1 for ver < ver2, 0 for ver1 == ver2, and 1 for ver1 > ver2.'''
  570.         return apt.VersionCompare(ver1, ver2)
  571.  
  572.     
  573.     def enabled(self):
  574.         '''Return whether Apport should generate crash reports.
  575.  
  576.         Signal crashes are controlled by /proc/sys/kernel/core_pattern, but
  577.         some init script needs to set that value based on a configuration file.
  578.         This also determines whether Apport generates reports for Python,
  579.         package, or kernel crashes.
  580.         
  581.         Implementations should parse the configuration file which controls
  582.         Apport (such as /etc/default/apport in Debian/Ubuntu).
  583.         '''
  584.         
  585.         try:
  586.             conf = open(self.configuration).read()
  587.         except IOError:
  588.             return True
  589.  
  590.         return re.search('^\\s*enabled\\s*=\\s*0\\s*$', conf, re.M) is None
  591.  
  592.     
  593.     def deb_without_preinst(klass, deb):
  594.         '''Return .deb without a preinst script.
  595.  
  596.         If given .deb file has a preinst script, generate a <name>_noscript.deb
  597.         file without it and return that name; otherwise, return deb.
  598.         
  599.         If the modified deb already exists, its name is returned without recreating
  600.         it.
  601.         '''
  602.         ndeb = '/var/cache/apt/archives/%s_noscript%s' % os.path.splitext(os.path.basename(deb))
  603.         if os.path.exists(ndeb):
  604.             return ndeb
  605.         ar = subprocess.Popen([
  606.             'ar',
  607.             'p',
  608.             deb,
  609.             'control.tar.gz'], stdout = subprocess.PIPE)
  610.         control_tar = ar.communicate()[0]
  611.         if not ar.returncode == 0:
  612.             raise AssertionError
  613.         tar = subprocess.Popen([
  614.             'tar',
  615.             'tz',
  616.             './preinst'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  617.         tar.communicate(control_tar)
  618.         if tar.returncode != 0:
  619.             return deb
  620.         d = tempfile.mkdtemp()
  621.         d2 = tempfile.mkdtemp()
  622.         
  623.         try:
  624.             tar = subprocess.Popen([
  625.                 'tar',
  626.                 '-C',
  627.                 d,
  628.                 '-xz'], stdin = subprocess.PIPE)
  629.             tar.communicate(control_tar)
  630.             if not tar.returncode == 0:
  631.                 raise AssertionError
  632.             for s in ('preinst', 'postinst', 'prerm', 'postrm'):
  633.                 path = os.path.join(d, s)
  634.                 if os.path.exists(path):
  635.                     os.unlink(path)
  636.                     continue
  637.                 tar.returncode == 0
  638.             
  639.             control_tar_new = os.path.join(d2, 'control.tar.gz')
  640.             tar = subprocess.Popen([
  641.                 'tar',
  642.                 '-C',
  643.                 d,
  644.                 '-cz',
  645.                 '.'], stdin = subprocess.PIPE, stdout = open(control_tar_new, 'w'))
  646.             if not tar.wait() == 0:
  647.                 raise AssertionError
  648.             shutil.copy(deb, ndeb)
  649.             r = subprocess.Popen([
  650.                 'ar',
  651.                 'r',
  652.                 ndeb,
  653.                 control_tar_new])
  654.             if not r.wait() == 0:
  655.                 raise AssertionError
  656.         finally:
  657.             shutil.rmtree(d)
  658.             shutil.rmtree(d2)
  659.  
  660.         return ndeb
  661.  
  662.     deb_without_preinst = classmethod(deb_without_preinst)
  663.     
  664.     def fetch_unpack(klass, cache, fetchProgress, no_dpkg = False, verbosity = 0):
  665.         '''Fetch and unpack packages.
  666.         
  667.         The packages need to be marked for installation in the given
  668.         apt.Cache() object.
  669.         
  670.         fetchProgress must be a valid apt.progress.FetchProgress object.
  671.         '''
  672.         fetcher = apt.apt_pkg.GetAcquire(fetchProgress)
  673.         pm = apt.apt_pkg.GetPackageManager(cache._depcache)
  674.         
  675.         try:
  676.             res = cache._fetchArchives(fetcher, pm)
  677.         except IOError:
  678.             e = None
  679.             print >>sys.stderr, 'ERROR: could not fetch all archives:', e
  680.  
  681.         if verbosity:
  682.             so = sys.stderr
  683.         else:
  684.             so = subprocess.PIPE
  685.         for c in cache.getChanges():
  686.             for script in ('postinst', 'prerm', 'postrm'):
  687.                 
  688.                 try:
  689.                     os.unlink('/var/lib/dpkg/info/%s.%s' % (c.name, script))
  690.                 continue
  691.                 except OSError:
  692.                     subprocess.call if no_dpkg else [
  693.                         'dpkg',
  694.                         '--force-depends',
  695.                         '--force-overwrite',
  696.                         '--unpack']
  697.                     subprocess.call if no_dpkg else [
  698.                         'dpkg',
  699.                         '--force-depends',
  700.                         '--force-overwrite',
  701.                         '--unpack']
  702.                     continue
  703.                 
  704.  
  705.             
  706.         
  707.  
  708.     fetch_unpack = classmethod(fetch_unpack)
  709.  
  710. impl = __AptDpkgPackageInfo()
  711. if __name__ == '__main__':
  712.     import unittest
  713.     import gzip
  714.     
  715.     class _AptDpkgPackageInfoTest(unittest.TestCase):
  716.         
  717.         def setUp(self):
  718.             self.orig_conf = impl.configuration
  719.  
  720.         
  721.         def tearDown(self):
  722.             impl.configuration = self.orig_conf
  723.  
  724.         
  725.         def test_check_files_md5(self):
  726.             '''_check_files_md5().'''
  727.             td = tempfile.mkdtemp()
  728.             
  729.             try:
  730.                 f1 = os.path.join(td, 'test 1.txt')
  731.                 f2 = os.path.join(td, 'test:2.txt')
  732.                 sumfile = os.path.join(td, 'sums.txt')
  733.                 open(f1, 'w').write('Some stuff')
  734.                 open(f2, 'w').write('More stuff')
  735.                 open(sumfile, 'w').write('2e41290da2fa3f68bd3313174467e3b5  %s\n        f6423dfbc4faf022e58b4d3f5ff71a70  %s\n        ' % (f1[1:], f2))
  736.                 self.assertEqual(impl._check_files_md5(sumfile), [], 'correct md5sums')
  737.                 open(f1, 'w').write('Some stuff!')
  738.                 self.assertEqual(impl._check_files_md5(sumfile), [
  739.                     f1[1:]], 'file 1 wrong')
  740.                 open(f2, 'w').write('More stuff!')
  741.                 self.assertEqual(impl._check_files_md5(sumfile), [
  742.                     f1[1:],
  743.                     f2], 'files 1 and 2 wrong')
  744.                 open(f1, 'w').write('Some stuff')
  745.                 self.assertEqual(impl._check_files_md5(sumfile), [
  746.                     f2], 'file 2 wrong')
  747.                 self.assertEqual(impl._check_files_md5(open(sumfile).read()), [
  748.                     f2], 'file 2 wrong')
  749.             finally:
  750.                 shutil.rmtree(td)
  751.  
  752.  
  753.         
  754.         def test_get_version(self):
  755.             '''get_version().'''
  756.             self.assert_(impl.get_version('libc6').startswith('2'))
  757.             self.assertRaises(ValueError, impl.get_version, 'nonexisting')
  758.  
  759.         
  760.         def test_get_available_version(self):
  761.             '''get_available_version().'''
  762.             self.assert_(impl.get_available_version('libc6').startswith('2'))
  763.             self.assertRaises(ValueError, impl.get_available_version, 'nonexisting')
  764.  
  765.         
  766.         def test_get_dependencies(self):
  767.             '''get_dependencies().'''
  768.             d = impl.get_dependencies('bash')
  769.             self.assert_(len(d) > 2)
  770.             self.assert_('libc6' in d)
  771.             for dep in d:
  772.                 self.assert_(impl.get_version(dep))
  773.             
  774.             d = impl.get_dependencies('coreutils')
  775.             self.assert_(len(d) >= 1)
  776.             self.assert_('libc6' in d)
  777.             for dep in d:
  778.                 self.assert_(impl.get_version(dep))
  779.             
  780.             d = impl.get_dependencies('libc6')
  781.             self.assert_(len(d) >= 1)
  782.             for dep in d:
  783.                 self.assert_(impl.get_version(dep))
  784.             
  785.  
  786.         
  787.         def test_get_source(self):
  788.             '''get_source().'''
  789.             self.assertRaises(ValueError, impl.get_source, 'nonexisting')
  790.             self.assertEqual(impl.get_source('bash'), 'bash')
  791.             self.assertEqual(impl.get_source('libc6'), 'glibc')
  792.  
  793.         
  794.         def test_is_distro_package(self):
  795.             '''is_distro_package().'''
  796.             self.assertRaises(ValueError, impl.is_distro_package, 'nonexisting')
  797.             self.assert_(impl.is_distro_package('bash'))
  798.  
  799.         
  800.         def test_get_architecture(self):
  801.             '''get_architecture().'''
  802.             self.assertRaises(ValueError, impl.get_architecture, 'nonexisting')
  803.             d = subprocess.Popen([
  804.                 'dpkg',
  805.                 '--print-architecture'], stdout = subprocess.PIPE)
  806.             system_arch = d.communicate()[0].strip()
  807.             if not d.returncode == 0:
  808.                 raise AssertionError
  809.             self.assertEqual(impl.get_architecture('bash'), system_arch)
  810.  
  811.         
  812.         def test_get_files(self):
  813.             '''get_files().'''
  814.             self.assertRaises(ValueError, impl.get_files, 'nonexisting')
  815.             self.assert_('/bin/bash' in impl.get_files('bash'))
  816.  
  817.         
  818.         def test_get_file_package(self):
  819.             '''get_file_package() on installed files.'''
  820.             self.assertEqual(impl.get_file_package('/bin/bash'), 'bash')
  821.             self.assertEqual(impl.get_file_package('/bin/cat'), 'coreutils')
  822.             self.assertEqual(impl.get_file_package('/nonexisting'), None)
  823.  
  824.         
  825.         def test_get_file_package_uninstalled(self):
  826.             '''get_file_package() on uninstalled packages.'''
  827.             lsb_release = subprocess.Popen([
  828.                 'lsb_release',
  829.                 '-sc'], stdout = subprocess.PIPE)
  830.             release_name = lsb_release.communicate()[0].strip()
  831.             if not lsb_release.returncode == 0:
  832.                 raise AssertionError
  833.             basedir = tempfile.mkdtemp()
  834.             
  835.             try:
  836.                 mapdir = os.path.join(basedir, 'dists', release_name)
  837.                 os.makedirs(mapdir)
  838.                 print >>gzip.open(os.path.join(mapdir, 'Contents-%s.gz' % impl.get_system_architecture()), 'w'), '\n foo header\nFILE                                                    LOCATION\nusr/bin/frobnicate                                      foo/frob\nusr/bin/frob                                            foo/frob-utils\nbo/gu/s                                                 na/mypackage\n'
  839.                 self.assertEqual(impl.get_file_package('usr/bin/frob', False, mapdir), None)
  840.                 self.assertEqual(impl.get_file_package('usr/bin/frob', True, mapdir), 'frob-utils')
  841.                 self.assertEqual(impl.get_file_package('/usr/bin/frob', True, mapdir), 'frob-utils')
  842.                 impl.set_mirror('file:///foo/nonexisting')
  843.                 self.assertRaises(IOError, impl.get_file_package, 'usr/bin/frob', True)
  844.                 impl.set_mirror('file://' + basedir)
  845.                 self.assertEqual(impl.get_file_package('usr/bin/frob', True), 'frob-utils')
  846.                 self.assertEqual(impl.get_file_package('/usr/bin/frob', True), 'frob-utils')
  847.                 cache_dir = os.path.join(basedir, 'cache')
  848.                 os.mkdir(cache_dir)
  849.                 self.assertEqual(impl.get_file_package('usr/bin/frob', True, cache_dir), 'frob-utils')
  850.                 self.assertEqual(len(os.listdir(cache_dir)), 1)
  851.                 self.assert_(os.listdir(cache_dir)[0].startswith('Contents-'))
  852.                 self.assertEqual(impl.get_file_package('/bo/gu/s', True, cache_dir), 'mypackage')
  853.             finally:
  854.                 shutil.rmtree(basedir)
  855.  
  856.  
  857.         
  858.         def test_get_file_package_diversion(self):
  859.             '''get_file_package() for a diverted file.'''
  860.             p = subprocess.Popen('LC_ALL=C dpkg-divert --list | head -n 1', shell = True, stdout = subprocess.PIPE)
  861.             out = p.communicate()[0]
  862.             if not p.returncode == 0:
  863.                 raise AssertionError
  864.             if not out:
  865.                 raise AssertionError
  866.             fields = out.split()
  867.             file = fields[2]
  868.             pkg = fields[-1]
  869.             self.assertEqual(impl.get_file_package(file), pkg)
  870.  
  871.         
  872.         def test_get_system_architecture(self):
  873.             '''get_system_architecture().'''
  874.             arch = impl.get_system_architecture()
  875.             self.assertNotEqual(arch, '')
  876.             self.assert_('\n' not in arch)
  877.  
  878.         
  879.         def test_compare_versions(self):
  880.             '''compare_versions.'''
  881.             self.assertEqual(impl.compare_versions('1', '2'), -1)
  882.             self.assertEqual(impl.compare_versions('1.0-1ubuntu1', '1.0-1ubuntu2'), -1)
  883.             self.assertEqual(impl.compare_versions('1.0-1ubuntu1', '1.0-1ubuntu1'), 0)
  884.             self.assertEqual(impl.compare_versions('1.0-1ubuntu2', '1.0-1ubuntu1'), 1)
  885.             self.assertEqual(impl.compare_versions('1:1.0-1', '2007-2'), 1)
  886.             self.assertEqual(impl.compare_versions('1:1.0-1~1', '1:1.0-1'), -1)
  887.  
  888.         
  889.         def test_enabled(self):
  890.             '''enabled.'''
  891.             impl.configuration = '/nonexisting'
  892.             self.assertEqual(impl.enabled(), True)
  893.             f = tempfile.NamedTemporaryFile()
  894.             impl.configuration = f.name
  895.             f.write('# configuration file\nenabled = 1')
  896.             f.flush()
  897.             self.assertEqual(impl.enabled(), True)
  898.             f.close()
  899.             f = tempfile.NamedTemporaryFile()
  900.             impl.configuration = f.name
  901.             f.write('# configuration file\n  enabled =0  ')
  902.             f.flush()
  903.             self.assertEqual(impl.enabled(), False)
  904.             f.close()
  905.             f = tempfile.NamedTemporaryFile()
  906.             impl.configuration = f.name
  907.             f.write('# configuration file\nnothing here')
  908.             f.flush()
  909.             self.assertEqual(impl.enabled(), True)
  910.             f.close()
  911.  
  912.         
  913.         def test_get_kernel_pacakge(self):
  914.             '''get_kernel_package().'''
  915.             self.assert_('linux' in impl.get_kernel_package())
  916.  
  917.  
  918.     
  919.     try:
  920.         if subprocess.call([
  921.             'dpkg',
  922.             '--help'], stdout = subprocess.PIPE, stderr = subprocess.PIPE) == 0:
  923.             unittest.main()
  924.     except OSError:
  925.         pass
  926.  
  927.  
  928.